#include <pthread.h>// For Multithreading
#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define SERVER_PORT 5432
#define MAX_LINE 256
// thread1:sending message
void *send_func(void *arg){
    int sockfd =int (int)(long)arg;     //file descriptor
    char send_buf[MAX_LINE];            // send message
    while(true){
        //send_buf is null
        if (fgets(send_buf, MAX_LINE, stdin) == NULL){
            printf("no message\n");
            continue;
        }
        else{
            //error state
            if(send(sockfd, send_buf, sizeof(send_buf), 0) == -1){
                printf("send error\n");
                continue;
            }
            //normal
            else printf("Client: %s\n", send_buf);
        }
        //"quit" detection
        if (strncmp(send_buf, "quit", 4) == 0)break;     // shut down while receiving "quit"
    }
    pthread_exit(0);
}

// thread2:receiving message
void *recv_func(void *arg){
    int sockfd = (int)(long)arg;    //file descriptor
    char recv_buf[MAX_LINE];        //receive message
    while (true){
        //normal message
        if (recv(sockfd, recv_buf, sizeof(recv_buf), 0) > 0)printf("Server: %s\n", recv_buf);
        // "quit" detection
        if (strncmp(recv_buf, "quit", 4) == 0)break;
    }
}

int main(int argc, char* argv[]) {//number of parameters , parameter list
    int send_result, recv_result,s,len;;
    // declare two threads for sending message and receiving message
    pthread_t send_thread, recv_thread;
    char *host,buf[MAX_LINE];
    struct hostent *hp;
    struct sockaddr_in sin;

    if(argc == 2)host = argv[1];//two paras is normal, the second one is host
    else{
        fprintf(stderr, "only one\n");
        exit(1);
    }

    hp = gethostbyname(host);
    if(!hp){
        fprintf(stderr, "unknown host: %s\n", host);
        exit(1);
    }
    bzero((char*)&sin, sizeof(sin));        // fill every bite with 0
    sin.sin_family = AF_INET;               // use IPv4 address
    bcopy(hp->h_addr, (char*)&sin.sin_addr, hp->h_length);  // specific IP address
    sin.sin_port = htons(SERVER_PORT);   // port
    if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
        perror("simplex-talk: socket");
        exit(1);
    }
    if(connect(s, (struct sockaddr*)&sin, sizeof(sin)) < 0){
        perror("simplex-talk: connect");
        close(s);
        exit(1);
    }
    else{
        printf("Successfully connected!\n");
        printf("-----------------------------------\n");
    }
    send_result = pthread_create(&send_thread, NULL, send_func, (void*)(long)s);// call send_func
    recv_result = pthread_create(&recv_thread, NULL, recv_func, (void*)(long)s);// call recv_func
    if(send_result != 0){
        printf("Send_thread create failure\n");
        exit(1);
    }
    if(recv_result != 0){
        printf("Recv_thread create failure\n");
        exit(1);
    }
    //Blocking threading
    send_result = pthread_join(send_thread, NULL);
    recv_result = pthread_join(recv_thread, NULL);
    close(s);
    return 0;
}